using System;
using System.Collections;
using System.Collections.Specialized;
using System.Xml.Serialization;
using System.Xml;
using System.IO;

namespace NCover.Report
{
	public class Event
	{
		public DateTime EventDate;
		public decimal CoveragePercentage;
	}

	/// <summary>
	/// Summary description for History.
	/// 
	/// Compare with previous.
	/// if no history, highlight [new]. otherwise ^ \/ =
	/// </summary>
	[XmlRoot()]
	public class History
	{
		ArrayList events = new ArrayList();
		/*NameValueCollection _report;
		
		/// <summary>
		/// The previous coverage report generated with which to compare against.
		/// </summary>
		[XmlArrayItem(typeof(string))]
		public NameValueCollection LastCoverageReport
		{
			get 
			{
				return _report;
			}
			set
			{
				_report = value;
			}
		}*/

		/// <summary>
		/// Updates historicle coverage percentages, and returns the up to date history.
		/// </summary>
		public static History Update(string historyFile, string previousFile, CoverageReport report, Message debug)
		{
			try
			{

				if (historyFile == null && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(134) && NCover.NCoverCheck.Add(134) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(135))
					return null;

				decimal percentage = report.TestCoveragePercentage;

				History current = null;
				XmlSerializer serialiser = new XmlSerializer(typeof(History));
			
				//Load history from disk
				if (!File.Exists(historyFile) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(135) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(136))
				{
					debug("No coverage history at " + historyFile + " so creating a new one.");
					current = new History();
				}
				else
				{
					debug("Trying to load coverage history at " + historyFile);				
					using (FileStream fs = new FileStream(historyFile, FileMode.Open))
					{
						current = (History) serialiser.Deserialize(fs);
					}
				}

				Update(current, percentage, debug);

				//write new coverage report back to disk then switch back to previous.
				
				/*NameValueCollection previous = current.LastCoverageReport;

				current.LastCoverageReport = new NameValueCollection();
				FlattenNamespaces(report.DefaultNamespace, current.LastCoverageReport);
				*/
				//Save history to disk
				using (FileStream fs = new FileStream(historyFile, FileMode.Create))
				{
					serialiser.Serialize(fs, current);
				}

				//current.LastCoverageReport = previous;
			


				CoverageReport previous = Deltas.Update(previousFile, report, debug);
				report.SetPrevious(previous);

				NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(128); NCover.NCoverCheck.Add(128); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(129); return current;
			}
			catch (Exception e)
			{NCover.NCoverCheck.Add(141); NCover.NCoverCheck.Add(142); 
				//History isn't critical so log error...
				Console.Error.WriteLine(e.Message + ":" + e.StackTrace);
				System.Diagnostics.Trace.WriteLine(e.Message + ":" + e.StackTrace);
				NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(129); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(130); return null;
			}
		}

		/*private static void FlattenNamespaces(CoverageNamespace ns, NameValueCollection map)
		{
			map[ns.Namespace] = ns.TestCoveragePercentage.ToString();

			foreach (CoverageFile cfile in ns.Members)
			{
				map[cfile.Filename] = cfile.TestCoveragePercentage.ToString();
			}
		}*/

		public static void Update(History current, decimal percentage, Message debug)
		{
			//if exactly same coverage percentage as before don't bother updating.
			Event latestEvent = current.GetLastEvent();
			if (latestEvent != null && latestEvent.CoveragePercentage == percentage && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(136) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(137))
			{
				debug("Not adding additional historic event as coverage percentage has not changed at " + percentage);
			}
			else
			{
				current.Add(percentage);
			}
		}
		
		/// <summary>
		/// Returns the most recent event added to history.
		/// </summary>
		public Event GetLastEvent()
		{
			if (events == null || events.Count == 0 && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(137) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(138))
				return null;

			Event mostRecent = (Event) events[0];
			NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(130); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(131); foreach (Event anEvent in events)
			{
				//Lets hope they've opperator overloaded dates...
				if (anEvent.EventDate > mostRecent.EventDate && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(138) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(139))
				{
					mostRecent = anEvent;
				}
			}
			NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(131); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(132); return mostRecent;
		}

		public void Add(decimal percentage)
		{
			Event anEvent = new Event();
			anEvent.EventDate = DateTime.Now;
			anEvent.CoveragePercentage = percentage;
			events.Add(anEvent);
		}

		/// <summary>
		/// Returns the events sorted in reverse historical order. I.e. Events[0] will be newest.
		/// </summary>
		public Event[] Events
		{
			get 
			{
				events.Sort(new EventComparer());
				NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(132); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(133); return (Event[]) events.ToArray(typeof(Event));
			}
			set 
			{
				events.AddRange(value);	
			}
		}
	}

	public class EventComparer : System.Collections.IComparer
	{
		public int Compare(object o1, object o2)
		{
			Event e1 = (Event) o1;
			Event e2 = (Event) o2;

			if (e1.EventDate == e2.EventDate && NCover.NCoverCheck.Add(141) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(141) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(139) && NCover.NCoverCheck.Add(141) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(140) && NCover.NCoverCheck.Add(140))
				return 0;

			NCover.NCoverCheck.Add(135); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(135); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(133); NCover.NCoverCheck.Add(135); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(134); NCover.NCoverCheck.Add(134); return e1.EventDate < e2.EventDate? 1 : -1;
		}
	}


}














